#include "queue.h"
#include <strings.h>
#include <unistd.h>

INT32 queue_init (QUEUE_DESC *pQueueDesc ,INT32 attrSize ,INT32 queueSize , INT32 dataSiz)
{
    CHAR *data = NULL;
    void *attr = NULL;
    UINT32 i = 0;
    /* 队列大小 */
    pQueueDesc->dataQueue = (QUEUE_DATA_T *)malloc(sizeof(QUEUE_DATA_T) * queueSize);
    if (NULL == pQueueDesc->dataQueue){
        Error ("queue_init, (NULL == pQueueDesc->mdataQueue), malloc fail .");
        return ERROR;
    }
    bzero ((char *)pQueueDesc->dataQueue, sizeof (QUEUE_DATA_T) * queueSize);
    pQueueDesc->size = queueSize;
    pQueueDesc->dataSize = dataSiz;
    /* 数据区大小 */
    data = (CHAR *) malloc (dataSiz * queueSize);
    if (NULL == data){
        Error ("queue_init, (NULL == data), malloc fail .");
        free(pQueueDesc->dataQueue);
        return ERROR;
    }
    bzero ((CHAR *)data, dataSiz * queueSize);
    /* 初始化队列 */
    for(i = 0; i < queueSize; i++){
        pQueueDesc->dataQueue[i].data = data + i * dataSiz;;
        pQueueDesc->dataQueue[i].size = 0;
    }
    if(attrSize > 0){
        /* 属性区大小 */
        attr = (void *) malloc (attrSize * queueSize);
        if (NULL == data){
            Error ("queue_init, (NULL == attr data), malloc fail .");
            free(data);
            free(pQueueDesc->dataQueue);
            free(attr);
            return ERROR;
        }
        bzero ((void *)data, attrSize * queueSize);
        pQueueDesc->attrSize = attrSize;
        /* 初始化属性 */
        for(i = 0; i < queueSize; i++){
            pQueueDesc->dataQueue[i].attr = attr + i * attrSize;            
        }
    }
    pQueueDesc->valid = 1;
    return OK;
}
void queue_destroy (QUEUE_DESC *pQueueDesc)
{
    if(pQueueDesc){
        if(pQueueDesc->attrSize > 0 && pQueueDesc->dataQueue && pQueueDesc->dataQueue[0].attr)
            free(pQueueDesc->dataQueue[0].attr);
        if(pQueueDesc->dataQueue && pQueueDesc->dataQueue[0].data)
            free(pQueueDesc->dataQueue[0].data);
        if(pQueueDesc->dataQueue)
            free(pQueueDesc->dataQueue);  
        pQueueDesc->valid = 0;  
    }    
}
INT32 queue_read(QUEUE_DESC *pQueueDesc , void *attr ,CHAR *data)
{
    UINT32 dataLen = 0;
    
    if(!pQueueDesc || !pQueueDesc->valid)
        return 0;
    if(pQueueDesc->wPt == pQueueDesc->rPt){
        return 0;
    }

    dataLen = pQueueDesc->dataQueue[pQueueDesc->rPt].size;

    if (dataLen > pQueueDesc->dataSize){
        pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
        return 0;
    }
    bcopy ((CHAR *)pQueueDesc->dataQueue[pQueueDesc->rPt].data, data, dataLen);	//src-->dst
    bzero ((char *)pQueueDesc->dataQueue[pQueueDesc->rPt].data, pQueueDesc->dataSize);
    if(pQueueDesc->attrSize > 0 && attr){
        bcopy ((void *)pQueueDesc->dataQueue[pQueueDesc->rPt].attr, attr, pQueueDesc->attrSize);
        bzero ((char *)pQueueDesc->dataQueue[pQueueDesc->rPt].attr, pQueueDesc->attrSize);
    }	
    pQueueDesc->dataQueue[pQueueDesc->rPt].size = 0;
    pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
	
    return dataLen;
}
INT32 queue_write(QUEUE_DESC *pQueueDesc, void *attr ,CHAR *data, UINT32 size)
{
    UINT32 wPt = 0;
    if(!pQueueDesc || !pQueueDesc->valid)
        return 0;
    if (size > pQueueDesc->dataSize){
        Error ("queue_write max %d, size = %d, !",pQueueDesc->dataSize, size);
        return ERROR;
    }

    wPt = pQueueDesc->wPt;
    wPt ++;

    if((pQueueDesc->wPt + 1) == pQueueDesc->rPt){//isFull        
        return ERROR;
    }

    memcpy ((void *)pQueueDesc->dataQueue[pQueueDesc->wPt].data, (void *)data, size);
    pQueueDesc->dataQueue[pQueueDesc->wPt].size = size;
    if(pQueueDesc->attrSize > 0 && attr){
        memcpy ((void *)pQueueDesc->dataQueue[pQueueDesc->wPt].attr, attr, pQueueDesc->attrSize);
    }	
    
    pQueueDesc->wPt = (pQueueDesc->wPt + 1) % pQueueDesc->size;

    return OK;
}
void  queue_clean(QUEUE_DESC *pQueueDesc)
{
   UINT32 dataLen = 0;
   INT32 i = 0;
   
   if(!pQueueDesc || !pQueueDesc->valid)
       return ;
   for( i = 0 ; i < pQueueDesc->size;i++){
       if(pQueueDesc->wPt == pQueueDesc->rPt){
           return ;
       }

        dataLen = pQueueDesc->dataQueue[pQueueDesc->rPt].size;

        if (dataLen > pQueueDesc->dataSize) {          
            pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
            continue;
        }
        bzero ((char *)pQueueDesc->dataQueue[pQueueDesc->rPt].data, pQueueDesc->dataSize);
        if(pQueueDesc->attrSize > 0){
            bzero ((void *)pQueueDesc->dataQueue[pQueueDesc->rPt].attr, pQueueDesc->attrSize);
        }
        pQueueDesc->dataQueue[pQueueDesc->rPt].size = 0;	
        pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
    }
    return ;
}

CHAR* queue_query(QUEUE_DESC *pQueueDesc, void *attr , UINT32 *size)
{
    UINT32 dataLen = 0;
    
    if(!pQueueDesc || !pQueueDesc->valid)
        return NULL;
    if(pQueueDesc->wPt == pQueueDesc->rPt){
        return NULL;
    }

    dataLen = pQueueDesc->dataQueue[pQueueDesc->rPt].size;

    if (dataLen > pQueueDesc->dataSize){
        pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
        return NULL;
    }
    *size = dataLen;
   
    if(pQueueDesc->attrSize > 0 && attr){
        bcopy ((void *)pQueueDesc->dataQueue[pQueueDesc->rPt].attr, attr, pQueueDesc->attrSize);      
    }	
    return (CHAR*)pQueueDesc->dataQueue[pQueueDesc->rPt].data;
}
void queue_rmmove(QUEUE_DESC *pQueueDesc)
{
    UINT32 dataLen = 0;
    
    if(!pQueueDesc || !pQueueDesc->valid)
        return;
    if(pQueueDesc->wPt == pQueueDesc->rPt){
        return;
    }

    dataLen = pQueueDesc->dataQueue[pQueueDesc->rPt].size;

    if (dataLen > pQueueDesc->dataSize){
        pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
        return;
    }   
    bzero ((char *)pQueueDesc->dataQueue[pQueueDesc->rPt].data, pQueueDesc->dataSize);
    if(pQueueDesc->attrSize > 0 ){       
        bzero ((char *)pQueueDesc->dataQueue[pQueueDesc->rPt].attr, pQueueDesc->attrSize);
    }	
    pQueueDesc->dataQueue[pQueueDesc->rPt].size = 0;
    pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
	
    return;
}
UINT32 queue_curDataSize(QUEUE_DESC *pQueueDesc)
{
    UINT32 dataLen = 0;
    
    if(!pQueueDesc || !pQueueDesc->valid)
        return 0;
    if(pQueueDesc->wPt == pQueueDesc->rPt){
        return 0;
    }

    dataLen = pQueueDesc->dataQueue[pQueueDesc->rPt].size;

    if (dataLen > pQueueDesc->dataSize){
        pQueueDesc->rPt = (pQueueDesc->rPt + 1) % pQueueDesc->size;
        return 0;
    }
    
    return dataLen;
}

